package com.applet.applet_shangcheng.config;

import com.applet.applet_shangcheng.entity.Admin;
import com.applet.applet_shangcheng.entity.User;
import com.applet.applet_shangcheng.service.UserService;
import com.applet.applet_shangcheng.utlis.AppletUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
import org.springframework.web.bind.annotation.CrossOrigin;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Configuration
@CrossOrigin
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 忽略静态资源的访问
        web.ignoring().antMatchers("/resources/**");
    }

    // AuthenticationManager: 认证的核心接口.
    // AuthenticationManagerBuilder: 用于构建AuthenticationManager对象的工具.
    // ProviderManager: AuthenticationManager接口的默认实现类.
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 内置的认证规则
        // auth.userDetailsService(userService).passwordEncoder(new Pbkdf2PasswordEncoder("12345"));

        // 自定义认证规则
        // AuthenticationProvider: ProviderManager持有一组AuthenticationProvider,每个AuthenticationProvider负责一种认证.
        // 委托模式: ProviderManager将认证委托给AuthenticationProvider.
        auth.authenticationProvider(new AuthenticationProvider() {
            // Authentication: 用于封装认证信息的接口,不同的实现类代表不同类型的认证信息.
            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                String username = authentication.getName();
                String password = (String) authentication.getCredentials();

//                User user = userService.findUserByName(username);
                Admin user = userService.findUserByAdmin(username);
                if (user == null) {
                    throw new UsernameNotFoundException("账号不存在!");
                }

                password = AppletUtil.md5(password);
                if (!user.getPassword().equals(password)) {
                    throw new BadCredentialsException("密码不正确!");
                }

                // principal: 主要信息; credentials: 证书; authorities: 权限;
                return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
            }

            // 当前的AuthenticationProvider支持哪种类型的认证.
            @Override
            public boolean supports(Class<?> aClass) {
                // UsernamePasswordAuthenticationToken: Authentication接口的常用的实现类.
                return UsernamePasswordAuthenticationToken.class.equals(aClass);
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().sameOrigin();
        // 登录相关配置
        http.formLogin()
                .loginPage("/loginpage")
                .loginProcessingUrl("/login")
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        //response.sendRedirect(request.getContextPath() + "/index");
                        response.sendRedirect(request.getContextPath() + "/pages/main.html");
                        //=response.sendRedirect("http://localhost:8900/pages/main.html");
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                        request.setAttribute("error", e.getMessage());
                        request.getRequestDispatcher("/loginpage").forward(request, response);
                    }
                });

        // 退出相关配置
        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect(request.getContextPath() + "index.html");
                    }
                });

        // 授权配置
        http.authorizeRequests()
                .antMatchers(
                        "/pages/report_TodayOrder.html"
                        ,"/pages/Time.html"
                        ,"/pages/announcement.html"
                        ,"/pages/shufflingFigure.html"
                        ,"/pages/goods.html"
                        ,"/pages/integrals.html"
                        ,"/pages/integralgoods_class.html"
                ).hasAnyAuthority("admin", "senior","user")
                .antMatchers(
                        "/announcement/insertAnnouncement"
                        , "/announcement/updateStatus/**"
                        , "/announcement/deleteAnnouncement/**"
                        , "/announcement/updateAnnouncement"

                        , "/shufflingFigure/insertGoods"
                        , "/shufflingFigure/deleteGoods/**"
                        , "/shufflingFigure/updateStatus/**"
                        , "/shufflingFigure/updateGoods"


                        , "/cashDiscount/insert"
                        , "/cashDiscount/findAll"
                        , "/cashDiscount/updateCashDiscountByCode"

                        , "/goods/insertGoods"
                        , "/goods/updateGoods"
                        , "/goods/updateStatus/**"

                        , "/integral/insertGoods"
                        , "/integral/updateGoods"
                        , "/IntegralOrder/updateOrder"
                        , "/IntegralOrder/exchange"
                        , "/qualityCode/insertCode"

                       /* ,"/pages/report_TodayOrder.html"
                        ,"/pages/Time.html"
                        ,"/pages/announcement.html"
                        ,"/pages/shufflingFigure.html"
                        ,"/pages/goods.html"
                        ,"/pages/integrals.html"
                        ,"/pages/integralgoods_class.html"*/
                        ,"/pages/order.html"
                        ,"/pages/integral_order.html"
                        ).hasAnyAuthority("admin", "senior")
                .antMatchers(
                        "/senior",
                        "/goods/deleteGoods/*"
                        , "/integral/deleteGoods/*"
                        , "/IntegralOrder/deleteOrder/**"

                    /*    ,"/pages/report_TodayOrder.html"
                        ,"/pages/Time.html"

                        ,"/pages/announcement.html"
                        ,"/pages/shufflingFigure.html"
                        ,"/pages/goods.html"
                        ,"/pages/integrals.html"
                        ,"/pages/integralgoods_class.html"

                        ,"/pages/order.html"
                        ,"/pages/integral_order.html"*/

                        ,"/pages/user.html"
                        ,"/pages/report_member.html"
                        ,"/pages/admin_user.html"

                        ,"/pages/cashDiscount.html"
                        ,"/pages/qualityGoods.html"
                        ,"/pages/the_Rules.html"
                        ,"/pages/the_problem.html"
                        ).hasAnyAuthority("senior")
                .anyRequest().permitAll()
                .and().csrf().disable();
        //.and().exceptionHandling().accessDeniedPage("/denied");
        // 权限不够时的处理
        http.exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    // 没有登录
                    @Override
                    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                        String xRequestedWith = request.getHeader("x-requested-with");
                        if ("XMLHttpRequest".equals(xRequestedWith)) {
                            response.setContentType("application/plain;charset=utf-8");
                            PrintWriter writer = response.getWriter();
                            writer.write(AppletUtil.getJSONString(403, "你还没有登录哦!"));
                        } else {
                            response.sendRedirect(request.getContextPath() + "/loginpage");
                        }
                    }
                })
                .accessDeniedHandler(new AccessDeniedHandler() {
                    // 权限不足
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
                        String xRequestedWith = request.getHeader("x-requested-with");
                        if ("XMLHttpRequest".equals(xRequestedWith)) {
                            response.setContentType("application/plain;charset=utf-8");
                            PrintWriter writer = response.getWriter();
                            writer.write(AppletUtil.getJSONString(403, "你没有访问此功能的权限!"));
                        } else {
                            response.sendRedirect(request.getContextPath() + "/denied");
                        }
                    }
                });

      /*// 增加Filter,处理验证码
        http.addFilterBefore(new Filter() {
            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                HttpServletRequest request = (HttpServletRequest) servletRequest;
                HttpServletResponse response = (HttpServletResponse) servletResponse;
                if (request.getServletPath().equals("/login")) {
                    String verifyCode = request.getParameter("verifyCode");
                    if (verifyCode == null || !verifyCode.equalsIgnoreCase("1234")) {
                        request.setAttribute("error", "验证码错误!");
                        request.getRequestDispatcher("/loginpage").forward(request, response);
                        return;
                    }
                }
                // 让请求继续向下执行.
                filterChain.doFilter(request, response);
            }
        }, UsernamePasswordAuthenticationFilter.class);*/

        // 记住我
        http.rememberMe()
                .tokenRepository(new InMemoryTokenRepositoryImpl())
                .tokenValiditySeconds(6000 * 24 * 24)
                .userDetailsService(userService);
    }
}
